using System;
using System.Collections.Generic;
using System.Reflection;

namespace Middleware.Naming
{
    public class NamingImpl : RemoteObject, INaming
    {
        public static int DEAFULT_ID = -1;

        private static Dictionary<string, IList<RemoteObject>> serviceList =
            new Dictionary<string, IList<RemoteObject>>();

        public NamingImpl()
            : base(NamingImpl.DEAFULT_ID) {
            ObjectPooling.Add(this.ObjectID, this);
        }

        public void Bind(string serviceName, RemoteObject remoteObject) {
            if (!serviceList.ContainsKey(serviceName)) {
                serviceList.Add(serviceName, new List<RemoteObject>());
            }
            serviceList[serviceName].Add(remoteObject);
        }

        public void Unbind(int id) {
            foreach (IList<RemoteObject> list in serviceList.Values) {
                for (int j = 0; j < list.Count; j++) {
                    RemoteObject remoteObject = list[j];
                    if ((int)remoteObject.ObjectID == id) {
                        list.Remove(remoteObject);
                    }
                }
            }
        }

        public object Lookup(string serviceName) {
            if (!serviceList.ContainsKey(serviceName)) {
                return null;
            }
            IList<RemoteObject> objectList = serviceList[serviceName];
            if (objectList.Count == 0) {
                return null;
            }
            RemoteObject remoteObject = objectList[0];
            objectList.Remove(remoteObject);
            objectList.Add(remoteObject);
            return GetRemoteObjectStub(remoteObject);
        }

        private object GetRemoteObjectStub(RemoteObject remoteObject) {
            string typeName = remoteObject.GetType().FullName;
            string stubTypeName = typeName.Replace("Impl", "Stub");
            ConstructorInfo constructor = Assembly.GetAssembly(this.GetType()).GetType(stubTypeName).GetConstructor(new Type[] { typeof(RemoteObject) });
            return constructor.Invoke(new object[] { remoteObject });
        }
    }
}
